package cn.assumejson.springframework.beans.context.support;

import cn.assumejson.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator;
import cn.assumejson.springframework.beans.context.ApplicationContext;
import cn.assumejson.springframework.beans.context.ApplicationEvent;
import cn.assumejson.springframework.beans.context.ApplicationListener;
import cn.assumejson.springframework.beans.context.ConfigurableApplicationContext;
import cn.assumejson.springframework.beans.context.event.ApplicationEventMulticaster;
import cn.assumejson.springframework.beans.context.event.ContextClosedEvent;
import cn.assumejson.springframework.beans.context.event.ContextRefreshedEvent;
import cn.assumejson.springframework.beans.context.event.SimpleApplicationEventMulticaster;
import cn.assumejson.springframework.beans.factory.BeansException;
import cn.assumejson.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import cn.assumejson.springframework.beans.factory.config.BeanDefinition;
import cn.assumejson.springframework.beans.factory.config.BeanFactoryPostProcessor;
import cn.assumejson.springframework.beans.factory.config.BeanPostProcessor;
import cn.assumejson.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import cn.assumejson.springframework.beans.factory.support.BeanDefinitionRegistry;
import cn.assumejson.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import cn.assumejson.springframework.beans.factory.support.DefaultListableBeanFactory;
import cn.assumejson.springframework.core.io.DefaultResourceLoader;
import cn.hutool.core.lang.Assert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * 应用上下文抽象类实现
 * 该类封装了大部分实用逻辑。并且还包含了{@link DefaultListableBeanFactory} 中所有的操作BeanFactory的方法
 *
 * @author Mr. Li
 * @version 1.0
 * @since 1.0 2021/11/30 15:11
 */
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {

    private static final Logger log = LoggerFactory.getLogger(AbstractApplicationContext.class.getName());

    private ApplicationContext parent;

    private final List<BeanFactoryPostProcessor> beanFactoryPostProcessors = new ArrayList<>();

    public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";

    /**
     * 事件发布器
     */
    private ApplicationEventMulticaster applicationEventMulticaster;

    public AbstractApplicationContext(ApplicationContext parent) {
        this();
        setParent(parent);
    }

    private void setParent(ApplicationContext parent) {
        this.parent = parent;
    }

    public AbstractApplicationContext() {
    }


    @Override
    public void refresh() throws BeansException {
        // 刷新上下文环境
        prepareRefresh();

        // 获取工厂
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // 给BeanFactory填充属性
        prepareBeanFactory(beanFactory);
        try {

            // 调用我们的bean工厂的后置处理器
            invokeBeanFactoryPostProcessors(beanFactory);

            // BeanPostProcessor 需要提前于其他 Bean 对象实例化之前执行注册操作
            registerBeanPostProcessors(beanFactory);

            // 创建事件多播器
            initApplicationEventMulticaster();

            // 实例化剩下的所有单例Bean
            finishBeanFactoryInitialization(beanFactory);

            // 最后容器刷新 发布刷新事件(Spring cloud也是从这里启动的)
            finishRefresh();

        } catch (BeansException ex) {
            log.error("this refresh method is fail:{}", ex.getMessage());

            destroyBeans();

            throw ex;
        }
    }

    /**
     * 注册事件多播器
     */
    private void initApplicationEventMulticaster() {
        // 获取工厂
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();

        // 判断容器中是否存在事件多播器
        if (beanFactory.containsBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
            // 获取当前多播器
            this.applicationEventMulticaster = beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
        } else {
            this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
            // 注入到容器中
            beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
        }
    }

    private void finishRefresh() {
        Collection<ApplicationListener> listeners = getBeansOfType(ApplicationListener.class).values();
        for (ApplicationListener listener : listeners) {
            this.applicationEventMulticaster.addApplicationListener(listener);
        }
        // TODO 实现注解开发后的容器刷新完毕的时间发布
        // 发布刷新事件
        publishEvent(new ContextRefreshedEvent(this));
    }

    public void publishEvent(ApplicationEvent event) {
        applicationEventMulticaster.multicastEvent(event);
    }

    private void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
        //实例化剩余的单实例bean --> 循环遍历所有的bean定义，然后判断属性，根据具体的属性生产bean
        beanFactory.preInstantiateSingletons();
    }

    /**
     * 给BeanFactory赋值属性
     *
     * @param beanFactory
     */
    protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        // 注册ApplicationContextAware，所有该类的子类，都可以感知ApplicationContext 上下文对象
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
    }

    private void destroyBeans() {
        getBeanFactory().destroySingletons();
    }


    @Override
    public <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException {
        return getBeanFactory().getBeansOfType(type);
    }

    @Override
    public String[] getBeanDefinitionNames() {
        return new String[0];
    }

    private void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        Map<String, BeanPostProcessor> beanPostProcessorMap = beanFactory.getBeansOfType(BeanPostProcessor.class);
        // 判断当前所有的Bean 对象中是否包含BeanPostProcessor对象
        for (BeanPostProcessor beanPostProcessor : beanPostProcessorMap.values()) {
            // 判断是否存在AOP代理对象
            boolean assignableFrom = AbstractAutoProxyCreator.class.isAssignableFrom(beanPostProcessor.getClass());
            if (assignableFrom) {
                ((AbstractAutoProxyCreator) beanPostProcessor).setBeanFactory(beanFactory);
            }
            if (beanPostProcessor instanceof AutowiredAnnotationBeanPostProcessor) {
                ((AutowiredAnnotationBeanPostProcessor) beanPostProcessor).setBeanFactory(beanFactory);
            }

            beanFactory.addBeanPostProcessor(beanPostProcessor);
        }
    }

    private void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        List<BeanFactoryPostProcessor> beanFactoryPostProcessors = getBeanFactoryPostProcessors();
//        Map<String, BeanFactoryPostProcessor> beanFactoryBeans = beanFactory.getBeansOfType(BeanFactoryPostProcessor.class);

        BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;

        for (BeanFactoryPostProcessor factoryPostProcessor : beanFactoryPostProcessors) {
            // 注解开发，创建配置类的BeanDefinition
            if (factoryPostProcessor instanceof BeanDefinitionRegistryPostProcessor) {
                //进行强制转化
                BeanDefinitionRegistryPostProcessor registryProcessor =
                        (BeanDefinitionRegistryPostProcessor) factoryPostProcessor;
                registryProcessor.postProcessBeanDefinitionRegistry(registry);

            }
            // TODO 这里会进行进行所有操作的排序操作
            factoryPostProcessor.postProcessBeanFactory(beanFactory);
        }
    }

    private List<BeanFactoryPostProcessor> getBeanFactoryPostProcessors() {
        String[] beanDefinitionNames = this.getBeanFactory().getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            BeanDefinition beanDefinition = this.getBeanFactory().getBeanDefinition(beanDefinitionName);
            if (BeanFactoryPostProcessor.class.isAssignableFrom(beanDefinition.getBeanClass())) {
                addBeanFactoryPostProcessor((BeanFactoryPostProcessor) getBean(beanDefinitionName));
            }
        }

        return beanFactoryPostProcessors;
    }

    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        /*
         *  xml加载spring会在这里加载beanDefinition
         *  javaconfig只是刷新了beanFactory
         *
         *  该方法也是一个模板方法
         *  Spring 有两个实现，一个可以支持重复刷新，一个不支持
         */
        refreshBeanFactory();
        //返回我们的bean工厂
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();

        log.debug("Bean factory for :{} ", beanFactory);

        return beanFactory;
    }

    private void prepareRefresh() {
        log.info("Refreshing {} ", this);

        // 提供模板方法，用于启动时，往容器中添加环境变量
        initPropertySources();

        // TODO 校验

        // 创建工厂，并且注册BeanDefinition
        refreshBeanFactory();
    }

    protected abstract void refreshBeanFactory() throws BeansException;

    protected void initPropertySources() {
        // For subclasses: do nothing by default.
    }

    @Override
    public abstract ConfigurableListableBeanFactory getBeanFactory();

    //---------------------------------------------------------------------
    // Implementation of BeanFactory interface
    //---------------------------------------------------------------------

    @Override
    public Object getBean(String name) throws BeansException {
        return getBeanFactory().getBean(name);
    }

    @Override
    public Object getBean(String name, Object... args) throws BeansException {
        return getBeanFactory().getBean(name, args);
    }

    @Override
    public <T> T getBean(String name, Class<T> requiredType) {
        return getBeanFactory().getBean(name, requiredType);
    }

    @Override
    public boolean containsBeanDefinition(String beanName) {
        return getBeanFactory().containsBean(beanName);
    }

    @Override
    public boolean containsBean(String name) {
        return getBeanFactory().containsBean(name);
    }

    @Override
    public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor) {
        Assert.notNull(postProcessor, "BeanFactoryPostProcessor must not be null");
        this.beanFactoryPostProcessors.add(postProcessor);
    }

    @Override
    public void registerShutdownHook() {
        Runtime.getRuntime().addShutdownHook(new Thread(this::close));
    }

    @Override
    public void close() {
        // 发布关闭事件
        publishEvent(new ContextClosedEvent(this));

        getBeanFactory().destroySingletons();
    }

    @Override
    public ClassLoader getBeanClassLoader() {
        return getBeanFactory().getBeanClassLoader();
    }

    @Override
    public String[] getBeanNamesForType(Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
        if (includeNonSingletons && allowEagerInit) {
            return doGetBeanNamesForType(type);
        }
        return doGetBeanNamesForType(type);
    }

    private String[] doGetBeanNamesForType(Class<?> type) {
        Map<String, ?> beansOfType = this.getBeansOfType(type);
        return (String[]) beansOfType.keySet().toArray();
    }

    @Override
    public Class<?> getType(String name) {
        return this.getBeanFactory().getBeanDefinition(name).getBeanClass();
    }
}
